import React, { ForwardedRef, RefObject, useEffect, useImperativeHandle, useState } from 'react'

import { IFloatWrappedComponentRef, IFloatWrapperProps, IFloatWrapperRef } from './types'

/**
 * 浮层容器定义实现
 * @param ref 浮层实例
 * @param wrapperProps 浮层属性
 * @returns
 */
export function useFloatWrapper<P = {}>(
  ref: ForwardedRef<IFloatWrapperRef<P>>,
  wrapperProps: IFloatWrapperProps<P>,
  wrappedComponentRef?: RefObject<IFloatWrappedComponentRef>,
) {
  const [visible, setVisible] = useState(false);
  const [loading, setLoading] = useState(false);

  const [title, setTitle] = useState<React.ReactNode>();
  const [componentProps, setComponentProps] = useState<P>();

  // 确认操作逻辑
  const onOk = async (result: any) => {
    setLoading(true);

    const targetComponentProps = wrapperProps.componentProps ?? componentProps;

    try {
      const _result = await wrappedComponentRef?.current?.beforeOk?.(result);

      await wrapperProps.onOk?.(_result ?? result, targetComponentProps);
      setVisible(false);
    } catch (err) {
      console.error(err);
    } finally {
      setLoading(false);
    }
  };

  // 取消操作逻辑
  const onCancel = (...args: any[]) => {
    wrapperProps.onCancel?.(...args);
    setVisible(false);
  };

  // 实例挂载浮层操作接口
  useImperativeHandle(
    ref,
    (): IFloatWrapperRef<P> => ({
      open: openProps => {
        const { title: newTitle, props: newComponentProps } = openProps ?? {};

        setTitle(newTitle);
        setComponentProps(newComponentProps);

        setVisible(true);
      },
      close: onCancel,
    }),
  );

  const ret = [
    {
      loading,
      visible: wrapperProps.visible ?? visible,
      title: wrapperProps.title ?? title,
      componentProps: wrapperProps.componentProps ?? componentProps,
    },
    {
      onOk,
      onCancel,
      setTitle,
      setComponentProps,
    },
  ] as const;

  return ret;
}

/**
 * 浮层内容是否可渲染
 * @param visible 是否可见
 * @returns
 */
export function useFloatContentRenderable(
  visible: boolean,
  defaultValue?: boolean,
) {
  const [renderable, setRenderable] = useState(defaultValue || visible);

  useEffect(() => {
    if (!renderable && !!visible) {
      setRenderable(true);
    }
  }, [visible, renderable]);

  return renderable;
}
